/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
osThreadId_t receiveTaskHandle;

const uint16_t log_tx_fifo_length = 128;
CFIFO_TypeDef log_tx_fifo;
const uint16_t rf_tx_fifo_length = 512;
CFIFO_TypeDef rf_tx_fifo;

uint8_t crc8_table[256];

char Log_TX_Buffer[128];
uint8_t Cmd_Tx_Buffer[64], Cmd_Rx_Buffer[64];
uint8_t rf_tx_uartDmaBuffer[128],rf_rx_uartDmaBuffer[128],log_tx_uartDmaBuffer[128];
uint16_t len_rfTxBuffA = 0, len_rfTxBuffB = 0, rfTxBuffWrite = 0;
uint8_t rfTxBuffA[256], rfTxBuffB[256];
/* USER CODE END 0 */

UART_HandleTypeDef huart1;
UART_HandleTypeDef huart2;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;
DMA_HandleTypeDef hdma_usart2_rx;
DMA_HandleTypeDef hdma_usart2_tx;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */

  if (usartPRINTF_HANDLE.Instance == USART1) {
    CFIFO_Init(&log_tx_fifo, log_tx_fifo_length);
  }

  /* USER CODE END USART1_Init 2 */

}
/* USART2 init function */

void MX_USART2_UART_Init(void)
{

  /* USER CODE BEGIN USART2_Init 0 */

  /* USER CODE END USART2_Init 0 */

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 115200;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */

  /* USER CODE END USART2_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PB6     ------> USART1_TX
    PB7     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* USART1 DMA Init */
    /* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA2_Stream2;
    hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);

    /* USART1_TX Init */
    hdma_usart1_tx.Instance = DMA2_Stream7;
    hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
  else if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspInit 0 */

  /* USER CODE END USART2_MspInit 0 */
    /* USART2 clock enable */
    __HAL_RCC_USART2_CLK_ENABLE();

    __HAL_RCC_GPIOD_CLK_ENABLE();
    /**USART2 GPIO Configuration
    PD5     ------> USART2_TX
    PD6     ------> USART2_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

    /* USART2 DMA Init */
    /* USART2_RX Init */
    hdma_usart2_rx.Instance = DMA1_Stream5;
    hdma_usart2_rx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_rx.Init.Mode = DMA_NORMAL;
    hdma_usart2_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_usart2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart2_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart2_rx);

    /* USART2_TX Init */
    hdma_usart2_tx.Instance = DMA1_Stream6;
    hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart2_tx.Init.Mode = DMA_NORMAL;
    hdma_usart2_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_usart2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart2_tx);

    /* USART2 interrupt Init */
    HAL_NVIC_SetPriority(USART2_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspInit 1 */

  /* USER CODE END USART2_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PB6     ------> USART1_TX
    PB7     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);

    /* USART1 DMA DeInit */
    HAL_DMA_DeInit(uartHandle->hdmarx);
    HAL_DMA_DeInit(uartHandle->hdmatx);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
  else if(uartHandle->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspDeInit 0 */

  /* USER CODE END USART2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART2_CLK_DISABLE();

    /**USART2 GPIO Configuration
    PD5     ------> USART2_TX
    PD6     ------> USART2_RX
    */
    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_5|GPIO_PIN_6);

    /* USART2 DMA DeInit */
    HAL_DMA_DeInit(uartHandle->hdmarx);
    HAL_DMA_DeInit(uartHandle->hdmatx);

    /* USART2 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART2_IRQn);
  /* USER CODE BEGIN USART2_MspDeInit 1 */

  /* USER CODE END USART2_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
  HAL_UART_Transmit(&usartPRINTF_HANDLE, (uint8_t *)&ch, 1, 0xFFFF);
 
  return ch;
}

/**
 * @brief  Print formatted data to the UART using DMA, which can be used just as printf.
 * @param  format: Format string.
 * @param  ...: Additional arguments.
 * @retval int: Number of characters printed.
 */
int print_log(const char *format, ...)
{
  int16_t result = 0;
  va_list args;
  va_start(args, format);
  vsnprintf(Log_TX_Buffer, sizeof(Log_TX_Buffer), format, args);
  result = CFIFO_Write(&log_tx_fifo, (uint8_t *)Log_TX_Buffer, strlen(Log_TX_Buffer));
  va_end(args);

  if (HAL_UART_STATE_BUSY_TX != HAL_UART_GetState(&usartPRINTF_HANDLE) &&
      HAL_UART_STATE_BUSY_TX_RX != HAL_UART_GetState(&usartPRINTF_HANDLE))
  {
    int16_t dataLength = CFIFO_Read(&log_tx_fifo, log_tx_uartDmaBuffer, sizeof(log_tx_uartDmaBuffer)); // 读取数据到发送缓冲区
    HAL_UART_Transmit_DMA(&usartPRINTF_HANDLE, log_tx_uartDmaBuffer, dataLength);
  }
  return result;
}


/**
 * @brief  Set the UART baud rate.
 * @param  huart: Pointer to a UART_HandleTypeDef structure that contains
 *               the configuration information for the specified UART module.
 * @param  bound_rate: The desired baud rate.
 * @return HAL_StatusTypeDef: HAL_OK on success, HAL_ERROR on failure.
 */
HAL_StatusTypeDef UART_Set_BoundRate(UART_HandleTypeDef *huart, uint32_t bound_rate)
{
  if (huart == NULL || bound_rate < 12832 || bound_rate > 5250000)
  {
    return HAL_ERROR;
  }

  huart->Init.BaudRate = bound_rate;
  // huart->Init.WordLength = UART_WORDLENGTH_8B;
  // huart->Init.StopBits = UART_STOPBITS_1;
  // huart->Init.Parity = UART_PARITY_NONE;
  // huart->Init.Mode = UART_MODE_TX_RX;
  // huart->Init.HwFlowCtl = UART_HWCONTROL_NONE;
  // huart->Init.OverSampling = UART_OVERSAMPLING_16;

  return HAL_UART_Init(huart);
}

void CRC8_LookupTable_Init(uint8_t crc8_polynomial)
{
    uint8_t crc;
    // Generate lookup table for all possible byte values (0-255)
    for (uint16_t i = 0; i < 256; i++)
    {
        crc = i;
        // Process each bit
        for (uint8_t j = 0; j < 8; j++)
        {
            if (crc & 0x80)  // If MSB is set
            {
                crc = (crc << 1) ^ crc8_polynomial;
            }
            else
            {
                crc <<= 1;
            }
        }
        crc8_table[i] = crc;
    }
}

uint8_t CRC8_Calculate(uint8_t *data, uint16_t length)
{
    uint8_t crc = 0x00; // Initial CRC value
    for (uint16_t i = 0; i < length; i++)
    {
        crc = crc8_table[crc ^ data[i]]; // Update CRC using lookup table
    }
    return crc;
}

int8_t CRC8_Check(uint8_t *data, uint16_t size)
{
    uint16_t len = 0;
    for (uint16_t i = 0; i < size; i++)
    {
        if (data[i] == 0xAA && data[i+1] == 0xCC) // 查找结束符
        {
            len = i;
            break;
        }
    }

    if (len < 2) // 如果没有找到回车或换行符，或者长度小于3，返回错误
    {
        return -1; // CRC校验失败
    }

    // 计算CRC8值
    uint8_t crc = CRC8_Calculate(data, len - 1); // 计算除最后一个字节外的CRC8值

    if (crc == data[len - 1]) // 检查CRC8值是否匹配
    {
        return 0; // CRC校验通过
    }
    else
    {
        return -1; // CRC校验失败
    }
}

void UART_Cmd_Init(void)
{
  HAL_UARTEx_ReceiveToIdle_DMA(&usartRF_HANDLE, rf_rx_uartDmaBuffer, sizeof(rf_rx_uartDmaBuffer)); // 启动DMA接收

  if (usartRF_HANDLE.Instance == USART2) {
    __HAL_DMA_DISABLE_IT(&hdma_usart2_rx, DMA_IT_HT); // 禁用半满中断
    __HAL_DMA_DISABLE_IT(&hdma_usart2_tx, DMA_IT_HT); // 禁用半满中断
  }
  else if (usartRF_HANDLE.Instance == USART1) {
    __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT); // 禁用半满中断
    __HAL_DMA_DISABLE_IT(&hdma_usart1_tx, DMA_IT_HT); // 禁用半满中断
  }

  CRC8_LookupTable_Init(0x07); // 初始化CRC8查找表
}

void UART_Send_Cmd(uint8_t *cmd, uint16_t len)
{
  if (cmd == NULL || len == 0) return;
  if (len > sizeof(Cmd_Tx_Buffer)) return;

  memcpy(Cmd_Tx_Buffer, cmd, len);
  Cmd_Tx_Buffer[len] = CRC8_Calculate(Cmd_Tx_Buffer, len);    len++; // 计算CRC8并添加到末尾
  Cmd_Tx_Buffer[len ++] = 0xAA; 
  Cmd_Tx_Buffer[len ++] = 0xCC; // 添加结束符 

  taskENTER_CRITICAL();
  if (rfTxBuffWrite == 0) {
    memcpy((uint8_t*) (rfTxBuffA + len_rfTxBuffA), Cmd_Tx_Buffer, len);
    len_rfTxBuffA += len;
  } else {
    memcpy((uint8_t*) (rfTxBuffB + len_rfTxBuffB), Cmd_Tx_Buffer, len);
    len_rfTxBuffB += len;
  }
  taskEXIT_CRITICAL();
  
  // 如果当前没有正在进行的发送操作，则开始发送数据
  if (HAL_UART_STATE_BUSY_TX != HAL_UART_GetState(&usartRF_HANDLE) &&
      HAL_UART_STATE_BUSY_TX_RX != HAL_UART_GetState(&usartRF_HANDLE))
  {
    if (rfTxBuffWrite == 0) {
      HAL_UART_Transmit_DMA(&usartRF_HANDLE, rfTxBuffA, len_rfTxBuffA);
      len_rfTxBuffA = 0; // 发送后清空缓冲区
      rfTxBuffWrite = 1;
    } else {
      HAL_UART_Transmit_DMA(&usartRF_HANDLE, rfTxBuffB, len_rfTxBuffB);
      len_rfTxBuffB = 0; // 发送后清空缓冲区
      rfTxBuffWrite = 0;
    }
  }
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *uartHandle)
{
  if (uartHandle == &usartRF_HANDLE)
  {
    if (rfTxBuffWrite == 0 &&len_rfTxBuffA > 0) {
      HAL_UART_Transmit_DMA(&usartRF_HANDLE, rfTxBuffA, len_rfTxBuffA);
      len_rfTxBuffA = 0; // 发送后清空缓冲区
      rfTxBuffWrite = 1;
    } else {
      if (len_rfTxBuffB > 0) {
        HAL_UART_Transmit_DMA(&usartRF_HANDLE, rfTxBuffB, len_rfTxBuffB);
        len_rfTxBuffB = 0; // 发送后清空缓冲区
        rfTxBuffWrite = 0;
      }
    }
  }

  if (uartHandle == &usartPRINTF_HANDLE)
  {
    int16_t dataAvailable = CFIFO_Get_AvailableData(&log_tx_fifo);
    if (dataAvailable > 0)
    {
      dataAvailable = CFIFO_Read(&log_tx_fifo, log_tx_uartDmaBuffer, sizeof(log_tx_uartDmaBuffer)); // 读取数据到发送缓冲区
      HAL_UART_Transmit_DMA(&usartPRINTF_HANDLE, log_tx_uartDmaBuffer, dataAvailable);
    }
  }

}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *uartHandle, uint16_t RxXferSize)
{
  if (uartHandle == &usartRF_HANDLE)
  {
    memcpy(Cmd_Rx_Buffer, rf_rx_uartDmaBuffer, RxXferSize); // 复制接收到的数据到JSON_Rx_Buffer
    HAL_UARTEx_ReceiveToIdle_DMA(&usartRF_HANDLE, rf_rx_uartDmaBuffer, sizeof(rf_rx_uartDmaBuffer)); // 重新启动DMA接收
    osThreadFlagsSet(receiveTaskHandle, 0x01U);
  } 
}

/* USER CODE END 1 */
